// CUDA Kernel for edge detection

#include "edge_detection.h"

#define THRESHOLD 96

#define RGB_TO_GRAYSCALE(r, g, b) r*.30+g*.59+b*.11

__global__ void detect_edge_kernel(unsigned char* d_out, unsigned char* rgb, int height, int width)
{
	//int row = blockIdx.x * blockDim.x + threadIdx.x;
	//int col = blockIdx.y * blockDim.y + threadIdx.x;

	//int row = blockIdx.x * blockDim.x + threadIdx.x;
	//int col = blockIdx.y * blockDim.y + threadIdx.y;

	int row = blockIdx.x;
	int col = threadIdx.x;
	// each pixel is made up of 3 RGB values stored sequentially

	// luminance of the current pixel we are at
	int lum = RGB_TO_GRAYSCALE(rgb[row*width*3 + col*3], rgb[row*width*3 + col*3+1], rgb[row*width*3 + col*3+2]);

	if (row == 0)
	{
		if (col == 0)
		{
			// we are at the bottom left corner

			// pixel directly above
			if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else
			{
				// we have no edge
				d_out[row*width*3 + col*3] = 255;
				d_out[row*width*3 + col*3+1] = 255; 
				d_out[row*width*3 + col*3+2] = 255;
			}
		}
		else if(col == width)
		{
			// we are at the bottom right corner

			// pixel directly above
			if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// compare to top-left diagonal pixel
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel left
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else
			{
				// we have no edge
				d_out[row*width*3 + col*3] = 255;
				d_out[row*width*3 + col*3+1] = 255; 
				d_out[row*width*3 + col*3+2] = 255;
			}
		}
		else
		{
			// we are along the bottom edge

			// compare to top-left diagonal pixel
			if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel directly above
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel top-right diagonal
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel left
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel right
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else
			{
				// we have no edge
				d_out[row*width*3 + col*3] = 255;
				d_out[row*width*3 + col*3+1] = 255; 
				d_out[row*width*3 + col*3+2] = 255;
			}
		}
	}
	else if (row == height)
	{
		if (col == 0)
		{
			// we are at the top left corner

			// pixel right
			if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel directly below
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel bottom-right diagonal
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else
			{
				// we have no edge
				d_out[row*width*3 + col*3] = 255;
				d_out[row*width*3 + col*3+1] = 255; 
				d_out[row*width*3 + col*3+2] = 255;
			}
		}
		else if(col == width)
		{
			// we are at the top right corner

			// pixel left
			if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel bottom left
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel directly below
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else
			{
				// we have no edge
				d_out[row*width*3 + col*3] = 255;
				d_out[row*width*3 + col*3+1] = 255; 
				d_out[row*width*3 + col*3+2] = 255;
			}
		}
		else
		{
			// we are along the top edge

			// pixel left
			if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel right
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel bottom left
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel directly below
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			// pixel bottom-right diagonal
			else if (abs(lum - 
				RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
			{
				// we have an edge
				d_out[row*width*3 + col*3] = 0;
				d_out[row*width*3 + col*3+1] = 0; 
				d_out[row*width*3 + col*3+2] = 0;
			}
			else
			{
				// we have no edge
				d_out[row*width*3 + col*3] = 255;
				d_out[row*width*3 + col*3+1] = 255; 
				d_out[row*width*3 + col*3+2] = 255;
			}
		}
	}
	else if (col == 0)
	{
		// corner cases are covered by the row checks so
		// we just have edges

		// we are along the left edge
		// pixel directly above
		if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel top-right diagonal
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel right
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel directly below
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel bottom-right diagonal
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		else
		{
			// we have no edge
			d_out[row*width*3 + col*3] = 255;
			d_out[row*width*3 + col*3+1] = 255; 
			d_out[row*width*3 + col*3+2] = 255;
		}
	}
	else if (col == width)
	{
		// we are along the right edge

		// compare to top-left diagonal pixel
		if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel directly above
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel left
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel bottom left
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel directly below
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		else
		{
			// we have no edge
			d_out[row*width*3 + col*3] = 255;
			d_out[row*width*3 + col*3+1] = 255; 
			d_out[row*width*3 + col*3+2] = 255;
		}
	}
	else
	{
		// we are somewhere in the image so all 8 neighbors are available to be checked
		// compare to top-left diagonal pixel
		if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel directly above
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel top-right diagonal
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel left
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel right
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel bottom left
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel directly below
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		// pixel bottom-right diagonal
		else if (abs(lum - 
			RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
		{
			// we have an edge
			d_out[row*width*3 + col*3] = 0;
			d_out[row*width*3 + col*3+1] = 0; 
			d_out[row*width*3 + col*3+2] = 0;
		}
		else
		{
			// we have no edge
			d_out[row*width*3 + col*3] = 255;
			d_out[row*width*3 + col*3+1] = 255; 
			d_out[row*width*3 + col*3+2] = 255;
		}
	}
}

void EdgeDetectDevice(dim3 NumBlocks, dim3 NumThreads, unsigned char* d_rgb, unsigned char* d_out)
{
	//detect_edge_kernel <<<NumBlocks, NumThreads>>> (d_out, d_rgb, NumBlocks.x, NumBlocks.y);
	printf("Row: %d Col: %d\n", NumBlocks.x, NumBlocks.y);
	dim3 stuff (512);
	dim3 stuff2 (512);
	detect_edge_kernel <<<stuff, stuff2>>> (d_out, d_rgb, 512, 512);
	cudaThreadSynchronize();
}

void EdgeDetectOnHost(int rowCount, int colCount, unsigned char* d_rgb, unsigned char* d_out)
{
	for (int row = 0; row < rowCount ; row++)
	{
		for (int col = 0; col < colCount; col++)
		{
			// luminance of the current pixel we are at
			int lum = RGB_TO_GRAYSCALE(rgb[row*width*3 + col*3], rgb[row*width*3 + col*3+1], rgb[row*width*3 + col*3+2]);

			if (row == 0)
			{
				if (col == 0)
				{
					// we are at the bottom left corner

					// pixel directly above
					if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else
					{
						// we have no edge
						d_out[row*width*3 + col*3] = 255;
						d_out[row*width*3 + col*3+1] = 255; 
						d_out[row*width*3 + col*3+2] = 255;
					}
				}
				else if(col == width)
				{
					// we are at the bottom right corner

					// pixel directly above
					if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// compare to top-left diagonal pixel
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel left
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else
					{
						// we have no edge
						d_out[row*width*3 + col*3] = 255;
						d_out[row*width*3 + col*3+1] = 255; 
						d_out[row*width*3 + col*3+2] = 255;
					}
				}
				else
				{
					// we are along the bottom edge

					// compare to top-left diagonal pixel
					if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel directly above
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel top-right diagonal
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel left
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel right
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else
					{
						// we have no edge
						d_out[row*width*3 + col*3] = 255;
						d_out[row*width*3 + col*3+1] = 255; 
						d_out[row*width*3 + col*3+2] = 255;
					}
				}
			}
			else if (row == height)
			{
				if (col == 0)
				{
					// we are at the top left corner

					// pixel right
					if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel directly below
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel bottom-right diagonal
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else
					{
						// we have no edge
						d_out[row*width*3 + col*3] = 255;
						d_out[row*width*3 + col*3+1] = 255; 
						d_out[row*width*3 + col*3+2] = 255;
					}
				}
				else if(col == width)
				{
					// we are at the top right corner

					// pixel left
					if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel bottom left
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel directly below
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else
					{
						// we have no edge
						d_out[row*width*3 + col*3] = 255;
						d_out[row*width*3 + col*3+1] = 255; 
						d_out[row*width*3 + col*3+2] = 255;
					}
				}
				else
				{
					// we are along the top edge

					// pixel left
					if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel right
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel bottom left
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel directly below
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					// pixel bottom-right diagonal
					else if (abs(lum - 
						RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
					{
						// we have an edge
						d_out[row*width*3 + col*3] = 0;
						d_out[row*width*3 + col*3+1] = 0; 
						d_out[row*width*3 + col*3+2] = 0;
					}
					else
					{
						// we have no edge
						d_out[row*width*3 + col*3] = 255;
						d_out[row*width*3 + col*3+1] = 255; 
						d_out[row*width*3 + col*3+2] = 255;
					}
				}
			}
			else if (col == 0)
			{
				// corner cases are covered by the row checks so
				// we just have edges

				// we are along the left edge
				// pixel directly above
				if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel top-right diagonal
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel right
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel directly below
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel bottom-right diagonal
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				else
				{
					// we have no edge
					d_out[row*width*3 + col*3] = 255;
					d_out[row*width*3 + col*3+1] = 255; 
					d_out[row*width*3 + col*3+2] = 255;
				}
			}
			else if (col == width)
			{
				// we are along the right edge

				// compare to top-left diagonal pixel
				if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel directly above
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel left
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel bottom left
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel directly below
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				else
				{
					// we have no edge
					d_out[row*width*3 + col*3] = 255;
					d_out[row*width*3 + col*3+1] = 255; 
					d_out[row*width*3 + col*3+2] = 255;
				}
			}
			else
			{
				// we are somewhere in the image so all 8 neighbors are available to be checked
				// compare to top-left diagonal pixel
				if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col-1)*3], rgb[(row+1)*width*3 + (col-1)*3+1], rgb[(row+1)*width*3 + (col-1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel directly above
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + col*3], rgb[(row+1)*width*3 + col*3+1], rgb[(row+1)*width*3 + col*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel top-right diagonal
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row+1)*width*3 + (col+1)*3], rgb[(row+1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel left
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[row*width*3 + (col-1)*3], rgb[row*width*3 + (col-1)*3+1], rgb[row*width*3 + (col-1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel right
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[row*width*3 + (col+1)*3], rgb[row*width*3 + (col+1)*3+1], rgb[row*width*3 + (col+1)*3+1])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel bottom left
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col-1)*3], rgb[(row-1)*width*3 + (col-1)*3+1], rgb[(row-1)*width*3 + (col-1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel directly below
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + col*3], rgb[(row-1)*width*3 + col*3+1], rgb[(row-1)*width*3 + col*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				// pixel bottom-right diagonal
				else if (abs(lum - 
					RGB_TO_GRAYSCALE(rgb[(row-1)*width*3 + (col+1)*3], rgb[(row-1)*width*3 + (col+1)*3+1], rgb[(row+1)*width*3 + (col+1)*3+2])) < THRESHOLD)
				{
					// we have an edge
					d_out[row*width*3 + col*3] = 0;
					d_out[row*width*3 + col*3+1] = 0; 
					d_out[row*width*3 + col*3+2] = 0;
				}
				else
				{
					// we have no edge
					d_out[row*width*3 + col*3] = 255;
					d_out[row*width*3 + col*3+1] = 255; 
					d_out[row*width*3 + col*3+2] = 255;
				}
			}
		}
	}
}